#include <gtest/gtest.h>

#include <mutex>
#include <thread>

// 演示 std::scoped_lock 可以一次锁定多个互斥量，
// 自动按照无死锁策略获取锁，避免手动控制锁顺序。
TEST(ScopedLockTest, AvoidsDeadlockAcrossMutexes) {
    std::mutex m1;
    std::mutex m2;
    int sharedCounter = 0;

    auto worker = [&](int iterations) {
        for (int i = 0; i < iterations; ++i) {
            std::scoped_lock lock(m1, m2);
            ++sharedCounter;
        }
    };

    std::thread t1(worker, 500);
    std::thread t2(worker, 500);
    t1.join();
    t2.join();

    EXPECT_EQ(sharedCounter, 1000);
}

// 辅助结构：模拟订单系统中跨资源的更新
struct InventorySystem {
    std::mutex orderMutex;
    std::mutex stockMutex;
    int outstandingOrders = 0;
    int stockQuantity = 0;

    void processOrder(int orderQty) {
        // 同时锁住订单表与库存表，保证操作原子性
        std::scoped_lock guard(orderMutex, stockMutex);
        outstandingOrders += 1;   // 记录一笔新订单
        stockQuantity -= orderQty; // 减去对应库存
    }
};

// 测试 2：业务示例——订单处理系统需要同时动用两个受保护的资源
TEST(ScopedLockExamples, MultiResourceUpdateStaysConsistent) {
    InventorySystem system;
    system.stockQuantity = 10'000;

    constexpr int kThreadCount = 8;
    constexpr int kOrdersPerThread = 250;
    constexpr int kOrderQty = 3;

    std::vector<std::thread> workers;
    workers.reserve(kThreadCount);

    for (int i = 0; i < kThreadCount; ++i) {
        workers.emplace_back([&system] {
            for (int j = 0; j < kOrdersPerThread; ++j) {
                system.processOrder(kOrderQty);
            }
        });
    }

    for (auto& t : workers) {
        t.join();
    }

    // 计算所有线程总共处理的订单数量
    const int totalOrders = kThreadCount * kOrdersPerThread;
    const int totalStockConsumed = totalOrders * kOrderQty;

    EXPECT_EQ(system.outstandingOrders, totalOrders);
    EXPECT_EQ(system.stockQuantity, 10'000 - totalStockConsumed);
}